package com.h5lib.server;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.alibaba.fastjson.JSON;
import com.h5lib.server.Di.CoreConfig;
import com.h5lib.server.Di.UriMapping;
import com.h5lib.server.protocol.ClassPathProtocolProvider;
import com.h5lib.server.protocol.ProtocolRegister;
import com.h5lib.server.template.TemplateUtil;
import com.h5lib.server.template.TemplateVariable;

import fi.iki.elonen.NanoHTTPD;
import fi.iki.elonen.NanoHTTPD.Response.Status;

/**
 * 
 * 核心Web服务
 * @author framer
 *
 */
public class CoreWebServer extends NanoHTTPD{

	/**
	 * 默认
	 */
	public static final String MIME_DEFAULT_BINARY = "application/octet-stream";
	
    private static final Map<String, String> MIME_TYPES = new HashMap<String, String>() {/**
		 * 
		 */
		private static final long serialVersionUID = 8829193643652053724L;

	{
        put("css", "text/css");
        put("htm", "text/html");
        put("html", "text/html");
        put("xml", "text/xml");
        put("java", "text/x-java-source, text/java");
        put("md", "text/plain");
        put("txt", "text/plain");
        put("asc", "text/plain");
        put("gif", "image/gif");
        put("jpg", "image/jpeg");
        put("jpeg", "image/jpeg");
        put("png", "image/png");
        put("mp3", "audio/mpeg");
        put("m3u", "audio/mpeg-url");
        put("mp4", "video/mp4");
        put("ogv", "video/ogg");
        put("flv", "video/x-flv");
        put("mov", "video/quicktime");
        put("swf", "application/x-shockwave-flash");
        put("js", "application/javascript");
        put("pdf", "application/pdf");
        put("doc", "application/msword");
        put("ogg", "application/x-ogg");
        put("zip", "application/octet-stream");
        put("exe", "application/octet-stream");
        put("class", "application/octet-stream");
    }};
    
    /**
     * 拦截器
     */
    private List<Interceptor> interceptors = new ArrayList<Interceptor>();
    
    
	public CoreWebServer(int port){
		this(null,port,null);
	}
	
    public CoreWebServer(String host, int port, File file) {
        super(host, port);
        if(ProtocolRegister.getProtocolRegister().getDefaultProtocolProvider() == null){
        	ProtocolRegister.getProtocolRegister().setDefaultProtocolProvider(new ClassPathProtocolProvider());
        }
    }
    
	@Override
	public Response serve(IHTTPSession session) {
		super.serve(session);
        String uri = session.getUri();
        System.out.println(uri);
        ModelMap modelMap = new ModelMap();
		UriMapping uriMapping = CoreConfig.requestMapping.get(uri);
		if (uriMapping == null) {
			return new Response(Status.OK, getMimeTypeForFile(uri), 
					ProtocolRegister.getProtocolRegister().getDefaultProtocolProvider().getInputStream(uri));
		} else {
			try {
				//全局拦截器
				for (Interceptor interceptor : interceptors) {
					if(!interceptor.intercept(session)){
						Object o = interceptor.handleError(session);
						if(o instanceof Response ){
							return (Response)o;
						}
						else if(o instanceof String){
							return createResponse(modelMap, o);
						}
					}
				}
				//方法拦截器
				List<Interceptor> methodInterceptors = uriMapping.getInterceptors();
				for (Interceptor interceptor : methodInterceptors) {
					if(!interceptor.intercept(session)){
						Object o = interceptor.handleError(session);
						if(o instanceof Response ){
							return (Response)o;
						}
						else if(o instanceof String){
							return createResponse(modelMap, o);
						}
					}
				}
				
				Class<?> controller = uriMapping.getClazz();
				java.lang.reflect.Method method = uriMapping.getMethod();
				Class<?>[] parameterTypes = method.getParameterTypes();
				Object[] o = new Object[parameterTypes.length];
				for (int i = 0; i < parameterTypes.length; i++) {
					if (parameterTypes[i] == IHTTPSession.class) {
						o[i] = session;
					} else if (parameterTypes[i] == modelMap.getClass()) {
						o[i] = modelMap;
					} else {
						o[i] = null;
					}
				}
				Object object = CoreConfig.IOC.get(controller);
				if (object == null) { // 如果没有注入
					object = controller.newInstance(); // 手动new
				}
				Object invoke = method.invoke(object, o);
				if (invoke instanceof String) {
					return createResponse(modelMap, invoke);
				} else {
					return (Response) invoke;
				}

			}catch(Exception e){
				e.printStackTrace();
				return new Response(Status.BAD_REQUEST,MIME_TYPES.get("html"), "服务器异常");
			}
		}
		
	}
	
	/**
	 * 创建响应
	 * @param modelMap
	 * @param invoke
	 * @return
	 */
	private Response createResponse(ModelMap modelMap, Object invoke) {
		String key = invoke.toString(); //classpath://
		String content = null;
		int index = -1;
		if((index = key.indexOf(":")) == -1){
			//如果没有设置协议，使用默认协议
			content = ProtocolRegister.getProtocolRegister().getDefaultProtocolProvider().getText(key);
		}
		else{
			String protocol = key.substring(0, index+1);
			String protocolUri = key.substring(index+1,key.length());
			content = ProtocolRegister.getProtocolRegister().getProvider(protocol).getText(protocolUri);
		}
		List<TemplateVariable> vars = TemplateUtil.getVariables(content);
		for (Entry<String, Object> entry : modelMap.getMap().entrySet()) {
			TemplateUtil.setValue(vars, entry.getKey(), JSON.toJSONString(entry.getValue()));
		}
		return new Response(TemplateUtil.getResult(vars, content));
	}
    
	/**
	 * 获取Mime通过后缀
	 * @param uri
	 * @return
	 */
    protected String getMimeTypeForFile(String uri) {
        int dot = uri.lastIndexOf('.');
        String mime = null;
        if (dot >= 0) {
            mime = MIME_TYPES.get(uri.substring(dot + 1).toLowerCase());
        }
        return mime == null ? MIME_DEFAULT_BINARY : mime;
    }
    
	public String readIO(InputStream in){
		StringBuffer s = new StringBuffer();
		BufferedReader reader = null;
		try {
			reader = new BufferedReader(new InputStreamReader(in));
			String line = null;
			while((line=reader.readLine()) != null){
				s.append(line);
				s.append("\n");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			try {
				if(reader != null){
					reader.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return s.toString();
	}
    
    /**
     * 添加全局拦截器
     * @param interceptor
     */
	public void addInterceptor(Interceptor interceptor){
		interceptors.add(interceptor);
	}
	
}
